library(lubridate)
Attaching package: ‘lubridate’
The following object is masked from ‘package:base’:
date
Tutvu liiklusõnnetuste andmetega
skim(liiklusonnestused)
Numeric Variables
Character Variables
Kaupluste andmed sf formaati, et need kaardile kanda
# Eesti projektsiooni kirjeldus, mis on vajalik andmete kaardile kandmiseks
eesti_proj4 <- "+proj=lcc +lat_1=59.33333333333334 +lat_2=58 +lat_0=57.51755393055556 +lon_0=24 +x_0=500000 +y_0=6375000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"
kaubanduskeskused_sf <- kaubanduskeskused %>%
# muuda sf objektiks nii, et veerud lon ja lat on koordinaatidega
# crs väärtus 4326 annab õige projektsiooni
st_as_sf(coords = c("lon", "lat"), crs = 4326, remove = FALSE) %>%
# muuda eesti projektsiooni, et arvutused õigesti teha
st_transform(eesti_proj4)
# kanna näidis andmed kaardile
kaubanduskeskused_sf %>%
mapview()
Iga kaubanduskeskuse ümber 250m diameetriga buffer. Kasutan seda selleks, et tuvastada kaubanduskeskuse juures toimunud liiklusõnnetused.
kaubanduskeskuse_buffer <- kaubanduskeskused_sf %>%
select(-lat, -lon) %>%
st_buffer(dist = 250)
#
kaubanduskeskuse_buffer %>%
mapview()
Ainult parkimise ja tagurdamisega seotud liiklusõnnetused
liiklusonnestused_sf_parkimine <- liiklusonnestused_sf %>%
filter(str_detect(situatsiooni_tyyp, "parkim|tagurd"))
liiklusonnetused_parkimine <- liiklusonnestused %>%
filter(str_detect(situatsiooni_tyyp, "parkim|tagurd"))
Leia kõik õnnetused, mis on toimunud kaubanduskeskuste 250m diameetri sees. Lisa igale vastavale liiklusõnnetusele kaubanduskeskuse nimi eraldi veeruna.
Funktsioon, mis leiab iga kaubanduskeskuse piirkonnas toimunud avariide klastrid.
klasterda_parkimised <- function(kaubanduskeskus){
df <- onnetused_poega %>%
filter(nimi == kaubanduskeskus)
clusters <- hdbscan(df %>%
select(lat, lon), minPts = 8)
liiklusonnetused_klastriga <- df %>%
mutate(cluster = clusters$cluster)
return(liiklusonnetused_klastriga)
}
Leia kõigi kaubanduskeskuste piirkonnas toimunud parkimiste/tagurdamiste klastrid
kaubanduskeskused_vector <- onnetused_poega %>%
distinct(nimi) %>%
pull(nimi)
onnetused_klastritega <- map_df(kaubanduskeskused_vector,
possibly(klasterda_parkimised, NULL))
Leia igale kaubanduskeskusele kõige suurema õnnetuste arvuga klaster. Seda kasutan kaubanduskeskuste juures toimunud õnnetuste tunnusena.
top_klaster <- onnetused_klastritega %>%
filter(cluster != 0) %>%
group_by(nimi, cluster) %>%
mutate(n = n()) %>%
ungroup() %>%
group_by(nimi) %>%
filter(n == max(n))
Järjesta kaubanduskeskused liiklusõnnetuste arvu järgi
top_klaster %>%
distinct(nimi, n) %>%
arrange(desc(n))
Kanna tulemused kaardile
# Kanna kaardile kaubanduskeskused ja nende juures toimunud õnnetused
leaflet(top_klaster) %>%
addTiles() %>%
addCircleMarkers(
popup = ~as.character(cluster)) %>%
addCircleMarkers(pood$lon, pood$lat, color = "red")
Assuming 'lon' and 'lat' are longitude and latitude, respectively
Analüüsi kaubanduskeskuste juures toimunud õnnetusi
Kuna kuupäevad on algandmetes teksti formaadis, siis nende konvertimiseks date-time formaati on vaja eestikeelsed kuu nimed asendada inglise keelsetega. Selleks tekita eraldi vastavauste tabel.
kuu_est_eng <- tribble(
~est, ~eng,
"juuli", "july",
"juuni", "june",
"mai", "may",
"aprill", "april",
"märts", "march",
"veebruar", "february",
"jaanuar", "january",
"detsember", "december",
"oktoober", "october"
)
Puhasta andmetes kupäeva ja kellaja veerud. Ümarda eraldi veerus kuupäev nädala ja kuu täpsusega. Selle põhjal saab teha pisut üldisemad graafikud.
Joonista interaktiivne graafik, mis näitab nädala täpsusega liiklusõnnetuste arvu.
Joonista interaktiivne graafik, mis näitab nädala täpsusega liiklusõnnetuste arvu.
top_klaster_kuu <- top_klaster_kuupaevaga %>%
count(kp_month)
# time series objekt
top_klaster_kuu_ts <- xts(x = top_klaster_kuu,
order.by = top_klaster_kuu$kp_month)
dygraph(top_klaster_kuu_ts) %>%
dyRangeSelector()
Tundide lõikes liiklusõõnetuste arv kaubanduskeskuste juures

Töötle kõiki parimisega seotud liiklusõnnetusi nii, et saaks lisada kuupäeva ja kellaaja
parkimine_kuupaevaga <- liiklusonnestused %>%
filter(str_detect(situatsiooni_tyyp, "parkim|tagurd")) %>%
ungroup() %>%
# leia kuu nimi, et selle järgi siduda ja asendada inglisekeelne nimetus
mutate(kuu = str_extract(kuupaev, "(?<=\\. )[[:alpha:]]*")) %>%
left_join(kuu_est_eng, by = c("kuu" = "est")) %>%
mutate(kuupaev_2 = str_replace(kuupaev, kuu, eng)) %>%
mutate(kp = str_extract(coalesce(kuupaev_2, kuupaev), "(?<=, ).*"),
kp = dmy(kp),
aeg = hms(kell)) %>%
select(-kuupaev_2, -eng, -kuu) %>%
arrange(kp) %>%
padr::thicken("week") %>% # lisa kuupäeva veerg, mis on nädala täpsusega
padr::thicken(by = "kp", "month") # lisa kuupäeva veerg, mis on kuu täpsusega
Some strings failed to parse, or all strings are NAs
Joonista kõigi parkimisega seotud õnnetuste kohta interaktiivne graafik, mis näitab nädala täpsusega liiklusõnnetuste arvu.
parkimine_nadal <- parkimine_kuupaevaga %>%
count(kp_week)
# time series objekt
parkimine_nadal_ts <- xts(x = parkimine_nadal,
order.by = parkimine_nadal$kp_week)
dygraph(parkimine_nadal_ts) %>%
dyRangeSelector()
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGphbml0b3IpCmxpYnJhcnkobWFwdmlldykKbGlicmFyeShzZikKbGlicmFyeShzcCkKbGlicmFyeShydmVzdCkKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KGdnbWFwKQpsaWJyYXJ5KHNraW1yKQpsaWJyYXJ5KGRic2NhbikKbGlicmFyeShsZWFmbGV0KQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShkeWdyYXBocykKbGlicmFyeSh4dHMpCmxpYnJhcnkocGFkcikKCmxvYWQoImRhdGEvbGlpa2x1c29ubmV0dXNlZF9rYXViYW5kdXNrZXNrdXNlZC5SRGF0YSIpCmBgYAoKVHV0dnUgbGlpa2x1c8O1bm5ldHVzdGUgYW5kbWV0ZWdhCmBgYHtyfQpza2ltKGxpaWtsdXNvbm5lc3R1c2VkKQpgYGAKCgpLYXVwbHVzdGUgYW5kbWVkIHNmIGZvcm1hYXRpLCBldCBuZWVkIGthYXJkaWxlIGthbmRhCmBgYHtyfQojIEVlc3RpIHByb2pla3RzaW9vbmkga2lyamVsZHVzLCBtaXMgb24gdmFqYWxpayBhbmRtZXRlIGthYXJkaWxlIGthbmRtaXNla3MKZWVzdGlfcHJvajQgPC0gIitwcm9qPWxjYyArbGF0XzE9NTkuMzMzMzMzMzMzMzMzMzQgK2xhdF8yPTU4ICtsYXRfMD01Ny41MTc1NTM5MzA1NTU1NiArbG9uXzA9MjQgK3hfMD01MDAwMDAgK3lfMD02Mzc1MDAwICtlbGxwcz1HUlM4MCArdG93Z3M4ND0wLDAsMCwwLDAsMCwwICt1bml0cz1tICtub19kZWZzIgoKa2F1YmFuZHVza2Vza3VzZWRfc2YgPC0ga2F1YmFuZHVza2Vza3VzZWQgJT4lIAogICMgbXV1ZGEgc2Ygb2JqZWt0aWtzIG5paSwgZXQgdmVlcnVkIGxvbiBqYSBsYXQgb24ga29vcmRpbmFhdGlkZWdhCiAgIyBjcnMgdsOkw6RydHVzIDQzMjYgYW5uYWIgw7VpZ2UgcHJvamVrdHNpb29uaQogIHN0X2FzX3NmKGNvb3JkcyA9IGMoImxvbiIsICJsYXQiKSwgY3JzID0gNDMyNiwgcmVtb3ZlID0gRkFMU0UpICU+JSAKICAjIG11dWRhIGVlc3RpIHByb2pla3RzaW9vbmksIGV0IGFydnV0dXNlZCDDtWlnZXN0aSB0ZWhhCiAgc3RfdHJhbnNmb3JtKGVlc3RpX3Byb2o0KQogIAojIGthbm5hIG7DpGlkaXMgYW5kbWVkIGthYXJkaWxlCmthdWJhbmR1c2tlc2t1c2VkX3NmICU+JSAKICBtYXB2aWV3KCkKYGBgCgpgYGB7cn0KbGlpa2x1c29ubmVzdHVzZWRfc2YgPC0gbGlpa2x1c29ubmVzdHVzZWQgJT4lIAogICMgbXV1ZGEgc2Ygb2JqZWt0aWtzIG5paSwgZXQgdmVlcnVkIGxvbiBqYSBsYXQgb24ga29vcmRpbmFhdGlkZWdhCiAgIyBjcnMgdsOkw6RydHVzIDQzMjYgYW5uYWIgw7VpZ2UgcHJvamVrdHNpb29uaQogIHN0X2FzX3NmKGNvb3JkcyA9IGMoImxvbiIsICJsYXQiKSwgY3JzID0gNDMyNiwgcmVtb3ZlID0gRkFMU0UpICU+JSAKICAjIG11dWRhIGVlc3RpIHByb2pla3RzaW9vbmksIGV0IGFydnV0dXNlZCDDtWlnZXN0aSB0ZWhhCiAgc3RfdHJhbnNmb3JtKGVlc3RpX3Byb2o0KQogIAojIGthbm5hIG7DpGlkaXMgYW5kbWVkIGthYXJkaWxlCmxpaWtsdXNvbm5lc3R1c2VkX3NmICU+JQogIGhlYWQoNTAwKSAlPiUgCiAgbWFwdmlldygpCmBgYAoKCklnYSBrYXViYW5kdXNrZXNrdXNlIMO8bWJlciAyNTBtIGRpYW1lZXRyaWdhIGJ1ZmZlci4KS2FzdXRhbiBzZWRhIHNlbGxla3MsIGV0IHR1dmFzdGFkYSBrYXViYW5kdXNrZXNrdXNlIGp1dXJlcyB0b2ltdW51ZCBsaWlrbHVzw7VubmV0dXNlZC4KYGBge3J9CmthdWJhbmR1c2tlc2t1c2VfYnVmZmVyIDwtIGthdWJhbmR1c2tlc2t1c2VkX3NmICU+JSAKICBzZWxlY3QoLWxhdCwgLWxvbikgJT4lIAogIHN0X2J1ZmZlcihkaXN0ID0gMjUwKSAKIyAKa2F1YmFuZHVza2Vza3VzZV9idWZmZXIgJT4lCiAgbWFwdmlldygpCmBgYAoKQWludWx0IHBhcmtpbWlzZSBqYSB0YWd1cmRhbWlzZWdhIHNlb3R1ZCBsaWlrbHVzw7VubmV0dXNlZApgYGB7cn0KbGlpa2x1c29ubmVzdHVzZWRfc2ZfcGFya2ltaW5lIDwtIGxpaWtsdXNvbm5lc3R1c2VkX3NmICU+JSAKICBmaWx0ZXIoc3RyX2RldGVjdChzaXR1YXRzaW9vbmlfdHl5cCwgInBhcmtpbXx0YWd1cmQiKSkKCmxpaWtsdXNvbm5ldHVzZWRfcGFya2ltaW5lIDwtIGxpaWtsdXNvbm5lc3R1c2VkICU+JSAKICBmaWx0ZXIoc3RyX2RldGVjdChzaXR1YXRzaW9vbmlfdHl5cCwgInBhcmtpbXx0YWd1cmQiKSkKYGBgCgoKCkxlaWEga8O1aWsgw7VubmV0dXNlZCwgbWlzIG9uIHRvaW11bnVkIGthdWJhbmR1c2tlc2t1c3RlIDI1MG0gZGlhbWVldHJpIHNlZXMuCkxpc2EgaWdhbGUgdmFzdGF2YWxlIGxpaWtsdXPDtW5uZXR1c2VsZSBrYXViYW5kdXNrZXNrdXNlIG5pbWkgZXJhbGRpIHZlZXJ1bmEuCmBgYHtyfQprYXViYW5kdXNrZXNrdXN0ZV9saWlrbHVzb25uZXR1c2VkIDwtIHN0X2pvaW4oa2F1YmFuZHVza2Vza3VzZV9idWZmZXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlpa2x1c29ubmVzdHVzZWRfc2ZfcGFya2ltaW5lKSAlPiUKICBkaXN0aW5jdChqdWh0dW1pX25yLCBuaW1pKQoKb25uZXR1c2VkX3BvZWdhIDwtIGxpaWtsdXNvbm5ldHVzZWRfcGFya2ltaW5lICU+JSAKICBpbm5lcl9qb2luKGthdWJhbmR1c2tlc2t1c3RlX2xpaWtsdXNvbm5ldHVzZWQpCgpvbm5ldHVzZWRfcG9lZ2EgJT4lIAogIHRhYnlsKG5pbWkpICU+JSAKICBhcnJhbmdlKGRlc2MobikpCmBgYAoKRnVua3RzaW9vbiwgbWlzIGxlaWFiIGlnYSBrYXViYW5kdXNrZXNrdXNlIHBpaXJrb25uYXMgdG9pbXVudWQgYXZhcmlpZGUga2xhc3RyaWQuCmBgYHtyfQprbGFzdGVyZGFfcGFya2ltaXNlZCA8LSBmdW5jdGlvbihrYXViYW5kdXNrZXNrdXMpewogIAogIGRmIDwtIG9ubmV0dXNlZF9wb2VnYSAlPiUgCiAgICBmaWx0ZXIobmltaSA9PSBrYXViYW5kdXNrZXNrdXMpCiAgCiAgY2x1c3RlcnMgPC0gaGRic2NhbihkZiAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QobGF0LCBsb24pLCBtaW5QdHMgPSA4KQogIAogIGxpaWtsdXNvbm5ldHVzZWRfa2xhc3RyaWdhIDwtIGRmICU+JQogICAgbXV0YXRlKGNsdXN0ZXIgPSBjbHVzdGVycyRjbHVzdGVyKQogIAogIHJldHVybihsaWlrbHVzb25uZXR1c2VkX2tsYXN0cmlnYSkKfQpgYGAKCkxlaWEga8O1aWdpIGthdWJhbmR1c2tlc2t1c3RlIHBpaXJrb25uYXMgdG9pbXVudWQgcGFya2ltaXN0ZS90YWd1cmRhbWlzdGUga2xhc3RyaWQKYGBge3J9CmthdWJhbmR1c2tlc2t1c2VkX3ZlY3RvciA8LSBvbm5ldHVzZWRfcG9lZ2EgJT4lIAogIGRpc3RpbmN0KG5pbWkpICU+JSAKICBwdWxsKG5pbWkpCgpvbm5ldHVzZWRfa2xhc3RyaXRlZ2EgPC0gbWFwX2RmKGthdWJhbmR1c2tlc2t1c2VkX3ZlY3RvciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zc2libHkoa2xhc3RlcmRhX3BhcmtpbWlzZWQsIE5VTEwpKQpgYGAKCkxlaWEgaWdhbGUga2F1YmFuZHVza2Vza3VzZWxlIGvDtWlnZSBzdXVyZW1hIMO1bm5ldHVzdGUgYXJ2dWdhIGtsYXN0ZXIuClNlZGEga2FzdXRhbiBrYXViYW5kdXNrZXNrdXN0ZSBqdXVyZXMgdG9pbXVudWQgw7VubmV0dXN0ZSB0dW5udXNlbmEuCmBgYHtyfQp0b3Bfa2xhc3RlciA8LSBvbm5ldHVzZWRfa2xhc3RyaXRlZ2EgJT4lIAogIGZpbHRlcihjbHVzdGVyICE9IDApICU+JSAKICBncm91cF9ieShuaW1pLCBjbHVzdGVyKSAlPiUgCiAgbXV0YXRlKG4gPSBuKCkpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIGdyb3VwX2J5KG5pbWkpICU+JSAKICBmaWx0ZXIobiA9PSBtYXgobiksICAjIGFpbnVsdCBrw7VpZ2Ugc3V1cmVtIGtsYXN0ZXIgasOkw6RiIGFsbGVzCiAgICAgICAgIG5fZGlzdGluY3QoY2x1c3RlcikgPCA1KSAgIyBhaW51bHQgbmVlZCwga2F1YmFuZHVza2Vza3VzZWQsIGt1cyBvbiBhbGxhIDUga2xhc3RyaQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgc2VsbGVnYSB2w6RsaXN0YW4gb3NhIGtlc2tsaW5uYSBrYXViYW5kdXNrZXNrdXNpCmBgYAoKSsOkcmplc3RhIGthdWJhbmR1c2tlc2t1c2VkIGxpaWtsdXPDtW5uZXR1c3RlIGFydnUgasOkcmdpCmBgYHtyfQp0b3Bfa2xhc3RlciAlPiUgCiAgZGlzdGluY3QobmltaSwgbikgJT4lIAogIGFycmFuZ2UoZGVzYyhuKSkKYGBgCgoKCkthbm5hIHR1bGVtdXNlZCBrYWFyZGlsZQoKYGBge3J9CiMgQWludWx0IG5lbmRlIGthdWJhbmR1c2tlc2t1c3RlIGtvb3JkaW5hYWRpZCwgbWlzIGVlbG5ldmFzIGFuYWzDvMO8c2lzIHbDpGxqYSB2YWxpc2luCnBvb2QgPC0ga2F1YmFuZHVza2Vza3VzZWQgJT4lIAogIGZpbHRlcihuaW1pICVpbiUgKHRvcF9rbGFzdGVyICU+JSAKICAgICAgICAgICBkaXN0aW5jdChuaW1pKSAlPiUgCiAgICAgICAgICAgcHVsbChuaW1pKSkpCgojIEthbm5hIGthYXJkaWxlIGthdWJhbmR1c2tlc2t1c2VkIGphIG5lbmRlIGp1dXJlcyB0b2ltdW51ZCDDtW5uZXR1c2VkCmxlYWZsZXQodG9wX2tsYXN0ZXIpICU+JSAKICBhZGRUaWxlcygpICU+JQogIGFkZENpcmNsZU1hcmtlcnMoCiAgICBwb3B1cCA9IH5hcy5jaGFyYWN0ZXIoY2x1c3RlcikpICU+JSAKICBhZGRDaXJjbGVNYXJrZXJzKHBvb2QkbG9uLCBwb29kJGxhdCwgY29sb3IgPSAicmVkIikKYGBgCgojIyBBbmFsw7zDvHNpIGthdWJhbmR1c2tlc2t1c3RlIGp1dXJlcyB0b2ltdW51ZCDDtW5uZXR1c2kKCkt1bmEga3V1cMOkZXZhZCBvbiBhbGdhbmRtZXRlcyB0ZWtzdGkgZm9ybWFhZGlzLCBzaWlzIG5lbmRlIGtvbnZlcnRpbWlzZWtzIGRhdGUtdGltZSBmb3JtYWF0aSBvbiB2YWphIGVlc3Rpa2VlbHNlZCBrdXUgbmltZWQgYXNlbmRhZGEgaW5nbGlzZSBrZWVsc2V0ZWdhLiAKU2VsbGVrcyB0ZWtpdGEgZXJhbGRpIHZhc3RhdmF1c3RlIHRhYmVsLgpgYGB7cn0Ka3V1X2VzdF9lbmcgPC0gdHJpYmJsZSgKICB+ZXN0LCB+ZW5nLAogICJqdXVsaSIsICJqdWx5IiwKICAianV1bmkiLCAianVuZSIsCiAgIm1haSIsICJtYXkiLAogICJhcHJpbGwiLCAiYXByaWwiLAogICJtw6RydHMiLCAibWFyY2giLAogICJ2ZWVicnVhciIsICJmZWJydWFyeSIsCiAgImphYW51YXIiLCAiamFudWFyeSIsCiAgImRldHNlbWJlciIsICJkZWNlbWJlciIsCiAgIm9rdG9vYmVyIiwgIm9jdG9iZXIiCikKYGBgCgpQdWhhc3RhIGFuZG1ldGVzIGt1cMOkZXZhIGphIGtlbGxhamEgdmVlcnVkLgrDnG1hcmRhIGVyYWxkaSB2ZWVydXMga3V1cMOkZXYgbsOkZGFsYSBqYSBrdXUgdMOkcHN1c2VnYS4gU2VsbGUgcMO1aGphbCBzYWFiIHRlaGEgcGlzdXQgw7xsZGlzZW1hZCBncmFhZmlrdWQuCmBgYHtyfQp0b3Bfa2xhc3Rlcl9rdXVwYWV2YWdhIDwtIHRvcF9rbGFzdGVyICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIHNlbGVjdCgtY2x1c3RlciwgLW4pICU+JSAKICAjIGxlaWEga3V1IG5pbWksIGV0IHNlbGxlIGrDpHJnaSBzaWR1ZGEgamEgYXNlbmRhZGEgaW5nbGlzZWtlZWxuZSBuaW1ldHVzCiAgbXV0YXRlKGt1dSA9IHN0cl9leHRyYWN0KGt1dXBhZXYsICIoPzw9XFwuIClbWzphbHBoYTpdXSoiKSkgJT4lIAogIGxlZnRfam9pbihrdXVfZXN0X2VuZywgYnkgPSBjKCJrdXUiID0gImVzdCIpKSAlPiUgCiAgbXV0YXRlKGt1dXBhZXZfMiA9IHN0cl9yZXBsYWNlKGt1dXBhZXYsIGt1dSwgZW5nKSkgJT4lIAogIG11dGF0ZShrcCA9IHN0cl9leHRyYWN0KGNvYWxlc2NlKGt1dXBhZXZfMiwga3V1cGFldiksICIoPzw9LCApLioiKSwKICAgICAgICAga3AgPSBkbXkoa3ApLAogICAgICAgICBhZWcgPSBobXMoa2VsbCkpICU+JSAKICBzZWxlY3QoLWt1dXBhZXZfMiwgLWVuZywgLWt1dSkgJT4lIAogIGFycmFuZ2Uoa3ApICU+JSAKICBwYWRyOjp0aGlja2VuKCJ3ZWVrIikgJT4lICAgIyBsaXNhIGt1dXDDpGV2YSB2ZWVyZywgbWlzIG9uIG7DpGRhbGEgdMOkcHN1c2VnYQogIHBhZHI6OnRoaWNrZW4oYnkgPSAia3AiLCAibW9udGgiKSAgIyBsaXNhIGt1dXDDpGV2YSB2ZWVyZywgbWlzIG9uIGt1dSB0w6Rwc3VzZWdhCgp0b3Bfa2xhc3Rlcl9rdXVwYWV2YWdhCmBgYAoKSm9vbmlzdGEgaW50ZXJha3RpaXZuZSBncmFhZmlrLCBtaXMgbsOkaXRhYiBuw6RkYWxhIHTDpHBzdXNlZ2EgbGlpa2x1c8O1bm5ldHVzdGUgYXJ2dS4KYGBge3J9CnRvcF9rbGFzdGVyX25hZGFsIDwtIHRvcF9rbGFzdGVyX2t1dXBhZXZhZ2EgJT4lIAogIGNvdW50KGtwX3dlZWspCgojIHRpbWUgc2VyaWVzIG9iamVrdAp0b3Bfa2xhc3Rlcl9uYWRhbF90cyA8LSB4dHMoeCA9IHRvcF9rbGFzdGVyX25hZGFsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyLmJ5ID0gdG9wX2tsYXN0ZXJfbmFkYWwka3Bfd2VlaykKCmR5Z3JhcGgodG9wX2tsYXN0ZXJfbmFkYWxfdHMpICU+JSAKICBkeVJhbmdlU2VsZWN0b3IoKQpgYGAKCkpvb25pc3RhIGludGVyYWt0aWl2bmUgZ3JhYWZpaywgbWlzIG7DpGl0YWIgbsOkZGFsYSB0w6Rwc3VzZWdhIGxpaWtsdXPDtW5uZXR1c3RlIGFydnUuCmBgYHtyfQp0b3Bfa2xhc3Rlcl9rdXUgPC0gdG9wX2tsYXN0ZXJfa3V1cGFldmFnYSAlPiUgCiAgY291bnQoa3BfbW9udGgpCgojIHRpbWUgc2VyaWVzIG9iamVrdAp0b3Bfa2xhc3Rlcl9rdXVfdHMgPC0geHRzKHggPSB0b3Bfa2xhc3Rlcl9rdXUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXIuYnkgPSB0b3Bfa2xhc3Rlcl9rdXUka3BfbW9udGgpCgpkeWdyYXBoKHRvcF9rbGFzdGVyX2t1dV90cykgJT4lIAogIGR5UmFuZ2VTZWxlY3RvcigpCmBgYAoKVHVuZGlkZSBsw7Vpa2VzIGxpaWtsdXPDtcO1bmV0dXN0ZSBhcnYga2F1YmFuZHVza2Vza3VzdGUganV1cmVzCmBgYHtyfQp0b3Bfa2xhc3Rlcl9rdXVwYWV2YWdhICU+JSAKICBtdXRhdGUodHVuZCA9IGhvdXIoYWVnKSkgJT4lIAogIGdncGxvdChhZXModHVuZCkpICsKICBnZW9tX2JhcigpCmBgYAoKClTDtsO2dGxlIGvDtWlraSBwYXJpbWlzZWdhIHNlb3R1ZCBsaWlrbHVzw7VubmV0dXNpIG5paSwgZXQgc2Fha3MgbGlzYWRhIGt1dXDDpGV2YSBqYSBrZWxsYWFqYQpgYGB7cn0KcGFya2ltaW5lX2t1dXBhZXZhZ2EgPC0gbGlpa2x1c29ubmVzdHVzZWQgJT4lIAogIGZpbHRlcihzdHJfZGV0ZWN0KHNpdHVhdHNpb29uaV90eXlwLCAicGFya2ltfHRhZ3VyZCIpKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICAjIGxlaWEga3V1IG5pbWksIGV0IHNlbGxlIGrDpHJnaSBzaWR1ZGEgamEgYXNlbmRhZGEgaW5nbGlzZWtlZWxuZSBuaW1ldHVzCiAgbXV0YXRlKGt1dSA9IHN0cl9leHRyYWN0KGt1dXBhZXYsICIoPzw9XFwuIClbWzphbHBoYTpdXSoiKSkgJT4lIAogIGxlZnRfam9pbihrdXVfZXN0X2VuZywgYnkgPSBjKCJrdXUiID0gImVzdCIpKSAlPiUgCiAgbXV0YXRlKGt1dXBhZXZfMiA9IHN0cl9yZXBsYWNlKGt1dXBhZXYsIGt1dSwgZW5nKSkgJT4lIAogIG11dGF0ZShrcCA9IHN0cl9leHRyYWN0KGNvYWxlc2NlKGt1dXBhZXZfMiwga3V1cGFldiksICIoPzw9LCApLioiKSwKICAgICAgICAga3AgPSBkbXkoa3ApLAogICAgICAgICBhZWcgPSBobXMoa2VsbCkpICU+JSAKICBzZWxlY3QoLWt1dXBhZXZfMiwgLWVuZywgLWt1dSkgJT4lIAogIGFycmFuZ2Uoa3ApICU+JSAKICBwYWRyOjp0aGlja2VuKCJ3ZWVrIikgJT4lICAgIyBsaXNhIGt1dXDDpGV2YSB2ZWVyZywgbWlzIG9uIG7DpGRhbGEgdMOkcHN1c2VnYQogIHBhZHI6OnRoaWNrZW4oYnkgPSAia3AiLCAibW9udGgiKSAgIyBsaXNhIGt1dXDDpGV2YSB2ZWVyZywgbWlzIG9uIGt1dSB0w6Rwc3VzZWdhCmBgYAoKSm9vbmlzdGEga8O1aWdpIHBhcmtpbWlzZWdhIHNlb3R1ZCDDtW5uZXR1c3RlIGtvaHRhIGludGVyYWt0aWl2bmUgZ3JhYWZpaywgbWlzIG7DpGl0YWIgbsOkZGFsYSB0w6Rwc3VzZWdhIGxpaWtsdXPDtW5uZXR1c3RlIGFydnUuCmBgYHtyfQpwYXJraW1pbmVfbmFkYWwgPC0gcGFya2ltaW5lX2t1dXBhZXZhZ2EgJT4lIAogIGNvdW50KGtwX3dlZWspCgojIHRpbWUgc2VyaWVzIG9iamVrdApwYXJraW1pbmVfbmFkYWxfdHMgPC0geHRzKHggPSBwYXJraW1pbmVfbmFkYWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXIuYnkgPSBwYXJraW1pbmVfbmFkYWwka3Bfd2VlaykKCmR5Z3JhcGgocGFya2ltaW5lX25hZGFsX3RzKSAlPiUgCiAgZHlSYW5nZVNlbGVjdG9yKCkKYGBgCg==